package org.taobao.ibatiside.ui.wizard;

import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.taobao.ibatiside.model.mapperv2.Mapperv2Factory;
import org.taobao.ibatiside.model.mapperv2.Mapperv2Package.Literals;
import org.taobao.ibatiside.model.mapperv2.Mapperv2Package;
import org.taobao.ibatiside.model.mapperv2.Parameter;
import org.taobao.ibatiside.model.mapperv2.ParameterMap;
import org.taobao.ibatiside.model.mapperv2.SqlMap;
import org.taobao.ibatiside.model.mapperv2.TypeAlias;
import org.taobao.ibatiside.ui.binding.UniqueParameterMapValidator;
import org.taobao.ibatiside.ui.util.ClassField;
import org.taobao.ibatiside.ui.util.MiscHelper;
import org.taobao.ibatiside.ui.util.TypeWrapper;
import org.taobao.ibatiside.ui.util.WorkspaceUtil;

public abstract class NewParameterMapComposite extends PageComposite {
	private static final String[] P_TYPE_HANDLER = new String[]{"typeHandler"};
	private static final String[] P_JDBC_TYPE = new String[]{"jdbcType"};
	private static final String[] P_JAVA_TYPE = new String[]{"javaType"};
	private static final String[] P_NULL_VALUE = {"nullValue"};
	private Text textParaMapId;
	private Text textClassFQN;
	private Table table;
	ParameterMap newParameterMap;
	private Binding id_binding;
	private Combo combo;
	private ComboViewer comboTypeWrapper;
	private TableViewer tableViewer;
	private List<TypeWrapper> typeWrappers;
	private Binding cls_binding;
	public NewParameterMapComposite(Composite parent, int style) {
		super(parent, style);
		
	}
	
	public NewParameterMapComposite(Composite parent, int style,
			BatisCommonPage page) {
		super(parent, style, page);
	}
	public void setFields(List<ClassField> fields) {
		newParameterMap.getParameter().clear();
		for (ClassField f : fields){
			Parameter p = Mapperv2Factory.eINSTANCE.createParameter();
			p.setProperty(f.getFieldName());
			newParameterMap.getParameter().add(p);
		}
		/*if (tableViewer.getInput() == null){
			tableViewer.setInput(newParameterMap.getParameter());
		}*/
		tableViewer.refresh();
	}
	@Override
	public void doNotifyChanged(Notification notification) {
		
	}
	@Override
	public void dispose() {
		super.dispose();
	}
	@Override
	protected void createContent() {
		initTypeWrappers();
		GridLayout gridLayout = new GridLayout(1, false);
		gridLayout.verticalSpacing = 0;
		gridLayout.marginHeight = 0;
		setLayout(gridLayout);
		
		Composite compContent = new Composite(this, SWT.NONE);
		compContent.setLayout(new FormLayout());
		GridData gd_compContent = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
		gd_compContent.heightHint = 300;
		compContent.setLayoutData(gd_compContent);
		
		Label lblId = new Label(compContent, SWT.NONE);
		lblId.setAlignment(SWT.RIGHT);
		FormData fd_lblId = new FormData();
		fd_lblId.right = new FormAttachment(0, 43);
		fd_lblId.top = new FormAttachment(0, 10);
		fd_lblId.left = new FormAttachment(0);
		lblId.setLayoutData(fd_lblId);
		lblId.setText("ID");
		
		textParaMapId = new Text(compContent, SWT.BORDER);
		FormData fd_textParaMapId = new FormData();
		fd_textParaMapId.left = new FormAttachment(lblId, 6);
		fd_textParaMapId.top = new FormAttachment(lblId, -3, SWT.TOP);
		textParaMapId.setLayoutData(fd_textParaMapId);
		
		Label lblClass = new Label(compContent, SWT.NONE);
		fd_textParaMapId.right = new FormAttachment(100, -454);
		FormData fd_lblClass = new FormData();
		fd_lblClass.top = new FormAttachment(lblId, 0, SWT.TOP);
		fd_lblClass.left = new FormAttachment(textParaMapId, 6);
		lblClass.setLayoutData(fd_lblClass);
		lblClass.setText("Class");
		
		textClassFQN = new Text(compContent, SWT.BORDER | SWT.READ_ONLY);
		
		FormData fd_textClassFQN = new FormData();
		fd_textClassFQN.right = new FormAttachment(100, -10);
		fd_textClassFQN.top = new FormAttachment(0, 7);
		textClassFQN.setLayoutData(fd_textClassFQN);
		
		tableViewer = new TableViewer(compContent, SWT.BORDER | SWT.FULL_SELECTION);
		table = tableViewer.getTable();
		table.setLinesVisible(true);
		table.setHeaderVisible(true);
		FormData fd_table = new FormData();
		fd_table.top = new FormAttachment(textParaMapId, 6);
		fd_table.bottom = new FormAttachment(100);
		fd_table.right = new FormAttachment(100, -10);
		fd_table.left = new FormAttachment(0);
		table.setLayoutData(fd_table);
		
		tableViewer.setContentProvider(new ArrayContentProvider());
		
		TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
		tableViewerColumn.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((Parameter)element).getProperty();
			}
		});
		TableColumn tblclmnNewColumn = tableViewerColumn.getColumn();
		tblclmnNewColumn.setWidth(100);
		tblclmnNewColumn.setText("Property");
		
		TableViewerColumn tableViewerColumn_1 = new TableViewerColumn(tableViewer, SWT.NONE);
		tableViewerColumn_1.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new TextCellEditor(table);
			}
			protected Object getValue(Object element) {
				return StringUtils.defaultString( ((Parameter)element).getNullValue() );
			}
			protected void setValue(Object element, Object value) {
				String str = (String) value;
				if (StringUtils.isNotBlank(str)){
					((Parameter)element).setNullValue(str);
					tableViewer.update(element, P_NULL_VALUE);
				}
			}
		});
		tableViewerColumn_1.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return ((Parameter)element).getNullValue();
			}
		});
		TableColumn tblclmnNullValue = tableViewerColumn_1.getColumn();
		tblclmnNullValue.setWidth(100);
		tblclmnNullValue.setText("Null Value");
		
		TableViewerColumn tableViewerColumn_2 = new TableViewerColumn(tableViewer, SWT.NONE);
		tableViewerColumn_2.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new ComboBoxCellEditor(table, MiscHelper.SQLMAP_INTERNAL_TYPE);
			}
			protected Object getValue(Object element) {
				return ArrayUtils.indexOf(MiscHelper.SQLMAP_INTERNAL_TYPE, ((Parameter)element).getJavaType());
			}
			protected void setValue(Object element, Object value) {
				int pos = ((Integer)value).intValue();
				if (-1 < pos && pos < MiscHelper.SQLMAP_INTERNAL_TYPE.length){
					((Parameter)element).setJavaType(MiscHelper.SQLMAP_INTERNAL_TYPE[pos]);
					tableViewer.update(element, P_JAVA_TYPE);
				}
			}
		});
		tableViewerColumn_2.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((Parameter)element).getJavaType();
			}
		});
		TableColumn tblclmnNewColumn_1 = tableViewerColumn_2.getColumn();
		tblclmnNewColumn_1.setWidth(100);
		tblclmnNewColumn_1.setText("Java Type");
		
		TableViewerColumn tableViewerColumn_3 = new TableViewerColumn(tableViewer, SWT.NONE);
		tableViewerColumn_3.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new ComboBoxCellEditor(table, MiscHelper.JDBC_TYPE);
			}
			protected Object getValue(Object element) {
				return ArrayUtils.indexOf(MiscHelper.JDBC_TYPE, ((Parameter)element).getJdbcType());
			}
			protected void setValue(Object element, Object value) {
				int pos = ((Integer)value).intValue();
				if (-1< pos && pos < MiscHelper.JDBC_TYPE.length){
					((Parameter)element).setJdbcType(MiscHelper.JDBC_TYPE[pos]);
					tableViewer.update(element, P_JDBC_TYPE);
				}
			}
		});
		tableViewerColumn_3.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((Parameter)element).getJdbcType();
			}
		});
		TableColumn tblclmnJdbcType = tableViewerColumn_3.getColumn();
		tblclmnJdbcType.setWidth(100);
		tblclmnJdbcType.setText("JDBC Type");
		
		TableViewerColumn tableViewerColumn_4 = new TableViewerColumn(tableViewer, SWT.NONE);
		tableViewerColumn_4.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new TypeSelectionCellEditor(((Parameter)element).getTypeHandler(), table, model.getCurrentProject(), IJavaSearchConstants.TYPE);
			}
			protected Object getValue(Object element) {
				String fqn = ((Parameter)element).getTypeHandler();
				if (StringUtils.isBlank(fqn)) return null;
					try {
						return model.getCurrentProject().findType(fqn);
					} catch (JavaModelException e) {
						e.printStackTrace();
					}
				return null;
			}
			protected void setValue(Object element, Object value) {
				if (element != null && value != null){
					String fqn = ((IType)value).getFullyQualifiedName();
					((Parameter)element).setTypeHandler(fqn);
					tableViewer.update(element, P_TYPE_HANDLER);
				}
			}
		});
		tableViewerColumn_4.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((Parameter)element).getTypeHandler();
			}
		});
		TableColumn tblclmnTypeHandler = tableViewerColumn_4.getColumn();
		tblclmnTypeHandler.setWidth(234);
		tblclmnTypeHandler.setText("Type Handler");
		
		comboTypeWrapper = new ComboViewer(compContent, SWT.NONE);
		combo = comboTypeWrapper.getCombo();
		fd_textClassFQN.left = new FormAttachment(combo, 6);
		FormData fd_combo = new FormData();
		fd_combo.left = new FormAttachment(lblClass, 4);
		fd_combo.right = new FormAttachment(100, -275);
		fd_combo.top = new FormAttachment(0, 5);
		combo.setLayoutData(fd_combo);
		
		comboTypeWrapper.setContentProvider(new ArrayContentProvider());
		comboTypeWrapper.setLabelProvider(new TypeWrapperLabelProvider());
		comboTypeWrapper.addSelectionChangedListener(new ISelectionChangedListener() {
			
			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				//alias, select and dataobject
				if (!event.getSelection().isEmpty()){
					TypeWrapper tw = (TypeWrapper) ((IStructuredSelection)event.getSelection()).getFirstElement();
					int cate = tw.getCategory();
					if (cate == TypeWrapper.TYPE_ALIAS){
						TypeAlias fqn = MiscHelper.getAliasByLiteral(model.getSqlmap(), tw.getTypeLiteral());
						if (fqn != null){
							try {
								IType alias_type = model.getCurrentProject().findType(fqn.getType());
								if (alias_type != null){
									textClassFQN.setText(alias_type.getFullyQualifiedName());
									setFields(MiscHelper.loadReadableFields(alias_type));
								}else{
									hostPage.setErrorMessage("Can't find type '"+fqn.getType()+"' for alias '"+fqn.getAlias()+"', please check it!");
								}
							} catch (JavaModelException e) {
								e.printStackTrace();
								hostPage.setErrorMessage("can't find alias "+tw.getTypeLiteral());
							}
						}
					}else if (cate == TypeWrapper.NEW_CREATE){
						if (model.getBeanNeedCreate()){
							textClassFQN.setText(WorkspaceUtil.getClassPathString(model.getConfigurationFile().getProject(), model.getBeanPath()));
							setFields(MiscHelper.toBeClassField(model.getBeanFields()));
						}
					}else if (cate == TypeWrapper.SELECT){
						IType selected_type = WorkspaceUtil.openType2(getShell(),model.getCurrentProject(),false);
						if (selected_type != null){
							textClassFQN.setText(selected_type.getFullyQualifiedName());
							try {
								setFields(MiscHelper.loadJavaBeanFields(selected_type));
							} catch (JavaModelException e) {
								e.printStackTrace();
								hostPage.setErrorMessage("can't load bean "+selected_type.getFullyQualifiedName());
							}
						}
					}
				}
			}
		});
		Composite compFunc = new Composite(this, SWT.NONE);
		GridData gd_compFunc = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
		gd_compFunc.heightHint = 30;
		compFunc.setLayoutData(gd_compFunc);
		
		Button btnNewButton = new Button(compFunc, SWT.NONE);
		btnNewButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (allRight()){
					getDisplay().asyncExec(new Runnable() {
						public void run() {
							okPressed();
						}
					});
				}else{
					hostPage.setErrorMessage("Info is not completed or right!");
				}
			}
		});
		btnNewButton.setBounds(213, 0, 80, 27);
		btnNewButton.setText("Create");
		
		Button btnNewButton_1 = new Button(compFunc, SWT.NONE);
		btnNewButton_1.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				getDisplay().asyncExec(new Runnable() {
					public void run() {
						cancelPressed();
					}
				});
			}
		});
		btnNewButton_1.setBounds(310, 0, 80, 27);
		btnNewButton_1.setText("Close");
		comboTypeWrapper.setInput(typeWrappers);
	}
	private void initTypeWrappers() {
		typeWrappers = new ArrayList<TypeWrapper>();
		typeWrappers.add(MiscHelper.TYPEWRAPPER_SELECT_CATEGORY);
		typeWrappers.add(MiscHelper.TYPEWRAPPER_DO_CATEGORY);
		typeWrappers.add(MiscHelper.TYPEWRAPPER_ALIAS_CATEGORY);
	}

	protected abstract void okPressed();
	protected abstract void cancelPressed();
	protected boolean allRight() {
		return StringUtils.isNotBlank(newParameterMap.getId()) && MiscHelper.getParameterMapById(model.getSqlmap(), newParameterMap.getId()) == null && StringUtils.isNotBlank(newParameterMap.getClass_());
	}

	@Override
	protected void doPropertyChange(PropertyChangeEvent evt) {
		String pn = evt.getPropertyName();
		if (BatisSettingModel.K_SQLMAP.equals(pn)) {
			SqlMap new_map = (SqlMap) evt.getNewValue();
			MiscHelper.removeAndAddNewTypeAlias(typeWrappers, new_map.getTypeAlias());
			comboTypeWrapper.refresh();
		} 
	}
	protected void dynamicBind(EMFDataBindingContext bindingContext) {
		UpdateValueStrategy s1 = new UpdateValueStrategy();
		s1.setAfterConvertValidator(new UniqueParameterMapValidator());
		IObservableValue textParaMapIdObserveTextObserveWidget = SWTObservables.observeText(textParaMapId, SWT.Modify);
		IObservableValue newParameterMapIdObserveValue = EMFObservables.observeValue(newParameterMap, Literals.PARAMETER_MAP__ID);
		id_binding = bindingContext.bindValue(textParaMapIdObserveTextObserveWidget, newParameterMapIdObserveValue, null, s1);
		
		ISWTObservableValue ob_control_paramap_cls = SWTObservables.observeText(textClassFQN, SWT.Modify);
		IObservableValue ob_model_paramap_cls = EMFObservables.observeValue(newParameterMap, Mapperv2Package.Literals.PARAMETER_MAP__CLASS);
		cls_binding = bindingContext.bindValue(ob_control_paramap_cls, ob_model_paramap_cls);
	}

	public void renew() {
		MiscHelper.disposeBinding(id_binding);
		MiscHelper.disposeBinding(cls_binding);
		newParameterMap = Mapperv2Factory.eINSTANCE.createParameterMap();
		tableViewer.setInput(newParameterMap.getParameter());
		textParaMapId.setText("");
		textClassFQN.setText("");
		dynamicBind(hostPage.getBindingContext());
	}
}
